import { readFileSync } from 'fs';
import { parallel, series } from 'gulp';
import { resolve } from 'path';
import {
  adjustViewBox,
  assignAttrsAtTag,
} from './plugins/svg2Definition/transforms';
import { generalConfig } from './plugins/svgo/presets';
import {
  clean,
  copy,
  generateEntry,
  generateIcons,
  generateInline,
} from './tasks/creators';
import { ExtractRegExp } from './tasks/creators/generateInline';
import { IconDefinition } from './templates/types';
import { getIdentifier } from './utils';

const iconDefinitionTemplate = readFileSync(
  resolve(__dirname, './templates/iconDefinition.ts.ejs'),
  'utf8',
);

const iconTemplate = readFileSync(
  resolve(__dirname, './templates/icon-react.tsx.ejs'),
  'utf8',
);

export default series(
  // 1. clean
  clean(['src', 'svg-generate']),

  parallel(
    // 2.1 copy helpers.ts, types.ts
    copy({
      from: ['templates/*.ts'],
      toDir: 'src',
    }),

    // 2.2 generate abstract node with the theme "filled"
    generateIcons({
      theme: 'normal',
      from: ['svg/*.svg'],
      toDir: 'src/iconDefinition',
      svgoConfig: generalConfig,
      extraNodeTransformFactories: [
        assignAttrsAtTag('svg', { focusable: 'false' }),
        adjustViewBox,
      ],
      stringify: JSON.stringify,
      template: iconDefinitionTemplate,
      mapToInterpolate: ({ name, content }) => ({
        identifier: getIdentifier({ name, themeSuffix: '' }),
        content,
      }),
      filename: ({ name }) => getIdentifier({ name, themeSuffix: '' }),
    }),

    generateIcons({
      theme: 'normal',
      from: ['svg/*.svg'],
      toDir: 'src/icons',
      svgoConfig: generalConfig,
      extraNodeTransformFactories: [
        assignAttrsAtTag('svg', { focusable: 'false' }),
        adjustViewBox,
      ],
      stringify: JSON.stringify,
      template: iconTemplate,
      mapToInterpolate: ({ name, content }) => ({
        identifier: getIdentifier({ name, themeSuffix: '' }),
        content,
      }),
      extname: '.tsx',
      filename: ({ name }) => getIdentifier({ name, themeSuffix: '' }),
    }),
  ),
  parallel(
    // 3.1 generate entry file: src/index.ts
    generateEntry({
      entryName: 'index.ts',
      from: ['src/icons/*.tsx'],
      toDir: 'src',
      banner: '// This index.ts file is generated automatically.\n',
      template: `export { default as <%= identifier %> } from '<%= path %>';`,
      mapToInterpolate: ({ name: identifier }) => ({
        identifier,
        path: `./icons/${identifier}`,
      }),
    }),

    // 3.2 generate inline SVG files
    generateInline({
      from: ['src/iconDefinition/*.ts'],
      toDir: () => `svg-generate/inline-svg`,
      getIconDefinitionFromSource: (content: string): IconDefinition => {
        const extract = ExtractRegExp.exec(content);
        if (extract === null || !extract[1]) {
          throw new Error('Failed to parse raw icon definition: ' + content);
        }
        return new Function(`return ${extract[1]}`)() as IconDefinition;
      },
    }),
    // 3.3 generate inline SVG files with namespace
    generateInline({
      from: ['src/iconDefinition/*.ts'],
      toDir: () => `svg-generate/inline-namespaced-svg`,
      getIconDefinitionFromSource: (content: string): IconDefinition => {
        const extract = ExtractRegExp.exec(content);
        if (extract === null || !extract[1]) {
          throw new Error('Failed to parse raw icon definition: ' + content);
        }
        return new Function(`return ${extract[1]}`)() as IconDefinition;
      },
      renderOptions: {
        extraSVGAttrs: { xmlns: 'http://www.w3.org/2000/svg' },
      },
    }),
  ),
);
